package com.anlogic.sdk.utils;

import java.io.File;
import java.net.URL;
import java.util.Collection;
import java.util.function.Consumer;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Drawable;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;

public class UIUtils {

	public static Device getDisplay() {
		return (Device) PlatformUI.getWorkbench().getDisplay();
	}

	public static Shell getActiveShell() {
		return PlatformUI.getWorkbench().getDisplay().getActiveShell();
	}

	public static void setShellImage(Shell shell, URL imageURL) {
		shell.setImage(ImageDescriptor.createFromURL(imageURL).createImage());
	}

	public static void showMessageDialog(String dialogTitle, String dialogMessage, int dialogImageType) {
		Shell shell = getActiveShell();
		MessageDialog dialog = new MessageDialog(shell, dialogTitle, null, dialogMessage, dialogImageType,
				new String[] { "Close" }, 0);
		dialog.open();
	}
	
	public static void showMessageDialogAsync(String dialogTitle, String dialogMessage, int dialogImageType) {
		Display.getDefault().asyncExec(new Runnable() {
			@Override
			public void run() {
				UIUtils.showMessageDialog(dialogTitle, dialogMessage, dialogImageType);
			}
		});
	}

	public static int convertWidthInCharsToPixels(Control control, int chars) {
		GC gc = new GC((Drawable) control);
		gc.setFont(JFaceResources.getDialogFont());
		FontMetrics fontMetrics = gc.getFontMetrics();
		gc.dispose();
		return Dialog.convertWidthInCharsToPixels(fontMetrics, chars);
	}

	public static int convertHeightInCharsToPixels(Control control, int chars) {
		GC gc = new GC((Drawable) control);
		gc.setFont(JFaceResources.getDialogFont());
		FontMetrics fontMetrics = gc.getFontMetrics();
		gc.dispose();
		return Dialog.convertHeightInCharsToPixels(fontMetrics, chars);
	}

	public static final String openNativeFolderDialog(String text, String filterPath, String prefKey) {
		IDialogSettings dialogSettings = UtilsPlugin.getDefault().getDialogSettings();
		DirectoryDialog dialog = new DirectoryDialog(getActiveShell());
		dialog.setText(text);
		if (!StringUtils.isNotEmpty(filterPath) && (new File(filterPath)).isDirectory())
			filterPath = dialogSettings.get(prefKey);
		if (StringUtils.isNotEmpty(filterPath))
			dialog.setFilterPath(filterPath);
		String choosenFile = dialog.open();
		if (choosenFile != null)
			dialogSettings.put(prefKey, choosenFile);
		return choosenFile;
	}

	public static final String openNativeFolderDialog(String text, String prefKey) {
		return openNativeFolderDialog(text, null, prefKey);
	}

	public static final String openNativeFileDialog(int style, String title, String prefKey, String[] extensions,
			String fileName, String filterPath) {
		IDialogSettings dialogSettings = UtilsPlugin.getDefault().getDialogSettings();
		String storedLocation = dialogSettings.get(prefKey);
		FileDialog dialog = new FileDialog(getActiveShell(), style);
		dialog.setFilterExtensions(extensions);
		dialog.setText(title);
		if (isValidFolderPath(filterPath)) {
			dialog.setFilterPath(filterPath);
		} else if (isValidFolderPath(storedLocation)) {
			dialog.setFilterPath(storedLocation);
		} else {
			String lastStoredLoc = dialogSettings.get("last_stored_selection");
			if (StringUtils.isEmpty(lastStoredLoc))
				lastStoredLoc = ResourcesPlugin.getWorkspace().getRoot().getLocationURI().getPath();
			dialog.setFilterPath(lastStoredLoc);
		}
		if (StringUtils.isNotEmpty(fileName))
			dialog.setFileName(fileName);
		String choosenFile = dialog.open();
		if (choosenFile != null) {
			File parentFile = (new File(choosenFile)).getParentFile();
			dialogSettings.put(prefKey, parentFile.getAbsolutePath());
			dialogSettings.put("last_stored_selection", parentFile.getAbsolutePath());
		}
		return choosenFile;
	}

	private static boolean isValidFolderPath(String filterPath) {
		return (StringUtils.isNotEmpty(filterPath) && (new File(filterPath)).isDirectory());
	}

	public static void setVisible(Control control, boolean visible) {
		if (control == null)
			return;
		control.setVisible(visible);
		Object layoutData = control.getLayoutData();
		if (layoutData == null) {
			layoutData = new GridData();
			control.setLayoutData(layoutData);
		}
		if (layoutData instanceof GridData) {
			((GridData) layoutData).exclude = !visible;
			control.getParent().layout();
		}
	}

	public static void excludeSingleWidget(Control control, boolean excludue) {
		if (control == null)
			return;
		control.setVisible(!excludue);
		Object layoutData = control.getLayoutData();
		if (layoutData == null) {
			layoutData = new GridData();
			control.setLayoutData(layoutData);
		}
		if (layoutData instanceof GridData) {
			((GridData) layoutData).exclude = excludue;
			control.getParent().layout();
		}
	}

	public static void excludeWidget(Control control) {
		excludeWidget(control, true);
	}

	public static void excludeWidget(Control mainControl, boolean exclude) {
		modifyUi(mainControl, control -> {
			if (control == null)
				return;
			control.setVisible(!exclude);
			Object data = control.getLayoutData();
			if (data == null) {
				data = new GridData();
				control.setLayoutData(data);
			}
			if (data instanceof GridData)
				((GridData) data).exclude = exclude;
		});
	}

	public static void setState(Control mainControl, boolean isEnabled) {
		modifyUi(mainControl, control -> {
			if (control == null)
				return;
			control.setEnabled(isEnabled);
		});
	}

	public static void modifyUi(Control control, Consumer<Control> uiConsumer) {
		if (control == null)
			return;
		uiConsumer.accept(control);
		modifyLinkedControlsUi(control, uiConsumer);
	}

	private static void modifyLinkedControlsUi(Control control, Consumer<Control> uiConsumer) {
		Object controlData = control.getData();
		if (controlData instanceof Control) {
			Control linkedControl = (Control) controlData;
			modifyUi(linkedControl, uiConsumer);
		} else if (controlData instanceof Collection) {
			Collection<?> linkedControls = (Collection<?>) controlData;
			for (Object linkedControl : linkedControls) {
				if (linkedControl instanceof Control)
					modifyUi((Control) linkedControl, uiConsumer);
			}
		}
	}

	public static int getButtonWidthHint(Button button) {
		PixelConverter converter = new PixelConverter((Control) button);
		int widthHint = converter.convertHorizontalDLUsToPixels(61);
		return Math.max(widthHint, (button.computeSize(-1, -1, true)).x);
	}

	public static void setButtonDimensionHint(Button button) {
		Object gd = button.getLayoutData();
		if (gd instanceof GridData)
			((GridData) gd).widthHint = getButtonWidthHint(button);
	}
}
